/*  iImager (network disk imaging via iscsi)
	Copyright (C) 2009-2010 Yao Wei <njustyw@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef QRWTHREAD_H
#define QRWTHREAD_H

#include <QtCore>
#include "lib_imaging.h"

struct	lib_imaging;
struct	device_handle;
struct	progress_t;
class	HDObject;
class	QWriteThread;
class	QReadThread;
class	QVerifyThread;
class	QVerifySHA256Thread;

/** The collaborative buffer for synchronous among the reader, writier and verifier thread*/
struct Q_MT_BUFFER
{
	int					state;
	unsigned char*		aligned_buffer;
	long				read_size;
	struct hash_content	hash;
};

/** Allocate memory for the collaborative buffer */
struct Q_MT_BUFFER* allocate_qbuffer_for_thread_copy();

/** Initialize the collaborative buffer */
void initialize_qbuffer_state(struct Q_MT_BUFFER*, quint8);

/** Deallocate memory for the collaborative buffer */
void release_qbuffer_for_thread_copy(struct Q_MT_BUFFER*);

/** The mutex and wait condition for synchronous*/
struct Q_MT_LOCKER
{
	QMutex			buffer_mutex;
	QWaitCondition	read_cv;
	QWaitCondition	write_cv;
	QWaitCondition	verify_cv;
};	
 
/** Allocate memory of mutex and wait condition for synchronous*/
struct Q_MT_LOCKER* allocate_qlocker_for_thread_copy();

/** Deallocate memory of mutex and wait condition for synchronous*/
void release_qlocker_for_thread_copy(Q_MT_LOCKER*);


/** The shared param among the thread of reader, writier, and verifier*/
struct Q_MT_PARAM
{
	QReadThread*				readThread;
	QVerifyThread*				verifyThread;
	QWriteThread*				writeThread;
	struct Q_MT_BUFFER*			buffer;
	struct Q_MT_LOCKER*			locker;
	
	HDObject*					obj;
	
	struct device_handle*		device;
	struct lib_imaging*			handle;
	struct progress_t*			progress;
	
	QMutex						data_mutex;
	char						msg[256];
	char						err_r_msg[256];
	char						err_w_msg[256];
	QMutex						cond_mutex;
	QWaitCondition				pause_cond;
	QAtomicInt					isdrop;
	QAtomicInt					ispause;
};

/** Allocate the memory for shared param*/
struct Q_MT_PARAM* allocate_param_for_thread_copy();

/** Deallocate the memory for shared param*/
void release_param_for_thread_copy(struct Q_MT_PARAM*);

/** Initialize everything for disk mirror */
bool initialize_device_and_imaging_handle(Q_MT_PARAM* param, const QString& deviceName, const QString& fileName, 
										  int imagingType, int hashType);
/** Cleanup when error happened */
bool cleanup_device_and_imaging_handle(Q_MT_PARAM* param);

/** Thread for reading the hard disk*/
class QReadThread:public QThread
{
	Q_OBJECT
public:
	QReadThread(QObject* parent = 0);
	~QReadThread();

	/** Set the shared param among threads*/ 
	void setParam(struct Q_MT_PARAM* parm);

protected:
	/** Start running of this thread*/
	virtual void run();

signals:
	/** This signal is emitted when some error occurs during the process of imaging */
	void signal_exceptioned(HDObject*, char*, struct Q_MT_PARAM*);
	
	/** This signal is emitted when user cancel the taskManage of imaging */
	void signal_cancel(HDObject*, struct Q_MT_PARAM*);
	
	/** This signal is emitted to notify the percentage, mean speed, elapsed time and remaining time during imaging*/
	void signal_updateStatus(HDObject*, int, double, int, int);
private:
	struct Q_MT_PARAM* qparam;
};

/** Thread for writing to imaging file*/
class QWriteThread:public QThread
{
	Q_OBJECT
public:
	QWriteThread(QObject* parent = 0);
	~QWriteThread();

	/** Set the shared param among threads*/ 
	void setParam(struct Q_MT_PARAM* parm);

protected:
	/** Start running of this thread*/
	virtual void run();

signals:
	/** This signal is emitted when the taskManage of imaging is completed */
	void signal_finished(HDObject*, double, int, struct Q_MT_PARAM*);
	
	/** This signal is emitted when some error occurs during the process of imaging */
	void signal_exceptioned(HDObject*, char*, struct Q_MT_PARAM*);
	
	/** This signal is emitted when user cancel the taskManage of imaging */
	void signal_cancel(HDObject*, struct Q_MT_PARAM*);
	
	/** This signal is emitted to notify the percentage, mean speed, elapsed time and remaining time during imaging*/
	void signal_updateStatus(HDObject*, int, double, int, int);

private:
	struct Q_MT_PARAM* qparam;

};

/** Thread for verifying the imaging file*/
class QVerifyThread : public QThread
{
	Q_OBJECT
public:
	QVerifyThread(QObject* parent = 0);
	~QVerifyThread();

	/** Set the shared param among threads and the hash type mask*/ 
	void setParam(struct Q_MT_PARAM* parm, quint8 hashMask);

protected:
	/** Start running of this thread*/
	virtual void run();

private:
	struct Q_MT_PARAM* qparam;
	quint8 hashTypeMask;
};


#endif
